#include"array_list.h"
#include<stdlib.h>
#include<string.h>

void __array_list_grow(array_list*);


int array_list_init(array_list* the_array_list,int the_init_size){

  the_array_list->head = 0;
  the_array_list->tail = -1;
  the_array_list->size = 0;
  the_array_list->array_size = the_init_size >= 1 ? the_init_size : 1;
  the_array_list->array = malloc(sizeof(void*) * the_array_list->array_size);
  return 0;
}

void* array_list_get(array_list* the_array_list, int the_index){
  void* item = 0;
  if(the_array_list->size > 0 && the_index < the_array_list->size && the_index >= 0 ){
    item = the_array_list->array[(the_array_list->head + the_index) % the_array_list->array_size];
  }
  return item;
}

void* array_list_remove(array_list* the_array_list, int the_index){
  void* item = 0;
  int act_index = 0;
  int i = 0;

  //if it is empty or they are asking for a non-existant index, just return 0
  if(the_array_list->size > 0 && the_index < the_array_list->size && the_index >= 0 ){

    act_index = (the_array_list->head + the_index) % the_array_list->array_size;

    item = the_array_list->array[act_index];

    the_array_list->size--;


    if(the_array_list->size <= 0){
      //if we made the list empty or it was already empty, might as well just put the head/tail back to initial.
      the_array_list->head = 0;
      the_array_list->tail = -1;
      the_array_list->size = 0;

    } else {

      for(i = act_index;i != the_array_list->tail; i = (i+1) % the_array_list->array_size){
        the_array_list->array[i] = the_array_list->array[(i+1) % the_array_list->array_size];
      }
      the_array_list->tail = (the_array_list->tail - 1 + the_array_list->size) % the_array_list->size;
    }
  }

  return item;
}

int array_list_add(array_list* the_array_list, void* the_item){
  int rv = 0;
  if(the_array_list->size == the_array_list->array_size){
          __array_list_grow(the_array_list);
  }

  the_array_list->tail = (the_array_list->tail + 1) % the_array_list->array_size;

  the_array_list->array[the_array_list->tail] = the_item;
  the_array_list->size++;
  return rv;
}

void array_list_destroy(array_list* the_array_list){
  free(the_array_list->array);
}


void array_list_destroy_data(array_list* the_array_list){
  int i = 0;
  for(i=0;i<the_array_list->size;i++){
    free(array_list_get(the_array_list, i));
  }
  free(the_array_list->array);
}

void __array_list_grow(array_list* the_array_list){
        int i = 0;
        int old_store_size = the_array_list->array_size;
        int items_to_move = old_store_size - the_array_list->head;
  int new_bytes = sizeof(void*) * the_array_list->array_size * 2;

  the_array_list->array = realloc(the_array_list->array, new_bytes);

        the_array_list->array_size *= 2;

        if(the_array_list->head > the_array_list->tail){
          //from head to the end of the old store.
          for(i = 0; i < items_to_move; i++){
            the_array_list->array[the_array_list->head + old_store_size + i] = the_array_list->array[the_array_list->head + i];
          }
          the_array_list->head += old_store_size;
        }
}
